#include "./WizVFSBlockStorageParam.hpp"
#include "./WizVFSBlockStorageChunk.hpp"

namespace Wiz
{
    namespace VFS
    {
        namespace BlockStorage
        {
            namespace Chunk
            {
                ::Wiz::Void::Type Type::WriteInfoAndAdvance(::Wiz::VFS::BlockStorage::Param::InOut IOParam)
                {
                    IOParam.m_AccessorPtr->MoveTo(m_Position);
                    ::Wiz::VFS::BlockStorage::ChunkInfo::Type ChunkInfo;

                    ChunkInfo.m_CountAvailable = m_CountAvailable;
                    ChunkInfo.m_FirstAvailable = m_FirstAvailable;
                    ChunkInfo.WriteAndAdvance(IOParam.m_AccessorPtr);
                }

                ::Wiz::Void::Type Type::ReadInfoAndAdvance(::Wiz::VFS::BlockStorage::Param::InOut IOParam)
                {
                    IOParam.m_AccessorPtr->MoveTo(m_Position);
                    ::Wiz::VFS::BlockStorage::ChunkInfo::Type ChunkInfo;

                    ChunkInfo.ReadAndAdvance(IOParam.m_AccessorPtr);
                    m_CountAvailable = ChunkInfo.m_CountAvailable;
                    m_FirstAvailable = ChunkInfo.m_FirstAvailable;
                }

                ::Wiz::Void::Type Type::Write(::Wiz::VFS::BlockStorage::Param::InOut IOParam)
                {
                    this->ReadInfoAndAdvance(IOParam);
                    ::Wiz::UInt32::Type OldCount = m_CountAvailable;

                    ::Wiz::VFS::BlockStorage::Block::Type VirtualBlock;

                    while ((m_CountAvailable > 0) && (IOParam.m_DataCurrPos < IOParam.m_DataSize))
                    {
                        VirtualBlock.SetPosition(m_Position, m_FirstAvailable, IOParam.m_BlockSizeComplete);
                        IOParam.m_LastWriteBlockID = m_FirstAvailable;
                        m_FirstAvailable = VirtualBlock.Write(IOParam);
                        IOParam.m_BlockInfo.m_PreBlockID = IOParam.m_LastWriteBlockID;
                        IOParam.m_BlockInfo.m_PreChunkID = IOParam.m_CurrChunkID;
                        m_CountAvailable--;
                    }

                    if (OldCount != m_CountAvailable)
                    {
                        IOParam.m_WriteBackChunkArray.PushBack(*this);
                    }
                }

                ::Wiz::Void::Type Type::Read(::Wiz::VFS::BlockStorage::Param::InOut IOParam)
                {
                    ::Wiz::VFS::BlockStorage::Block::Type VirtualBlock;

                    while ((IOParam.m_DataCurrPos > 0) && (IOParam.m_CurrChunkID == IOParam.m_BlockInfo.m_PreChunkID))
                    {
                        VirtualBlock.SetPosition(m_Position, IOParam.m_BlockInfo.m_PreBlockID, IOParam.m_BlockSizeComplete);
                        VirtualBlock.Read(IOParam);
                    }
                }

                ::Wiz::Void::Type Type::Remove(::Wiz::VFS::BlockStorage::Param::InOut IOParam)
                {
                    ::Wiz::VFS::BlockStorage::Block::Type VirtualBlock;
                    ::Wiz::Int::Type i = 0;
                    ::Wiz::UInt32::Type FB = IOParam.m_BlockInfo.m_PreBlockID;
                    while (IOParam.m_CurrChunkID == IOParam.m_BlockInfo.m_PreChunkID)
                    {
                        WIZ_ASSERT(i < IOParam.m_BlockCountPerChunk);
                        VirtualBlock.SetPosition(m_Position, IOParam.m_BlockInfo.m_PreBlockID, IOParam.m_BlockSizeComplete);
                        VirtualBlock.ReadInfoAndAdvance(IOParam);
                        i++;
                    }
                    if (i > 0)
                    {
                        ::Wiz::UInt32::Type Pos = VirtualBlock.m_Position;
                        IOParam.m_AccessorPtr->Move(Pos);
                        IOParam.m_AccessorPtr->Write(m_FirstAvailable);
                        m_CountAvailable += ++i;
                        m_FirstAvailable = FB;
                        WriteInfoAndAdvance(IOParam);
                    }
                }
            } /// end of namespace Chunk
        } /// end of namespace BlockStorage
    } /// end of namespace Accessor
} /// end of namespace Wiz

